<?php
/**
 * @Author: Marte
 * @Date:   2020-05-19 17:51:21
 * @Last Modified by:   Marte
 * @Last Modified time: 2020-07-11 08:19:18
 */

class Lock{
    protected $redis;

    public function __construct(){
        $this->redis = new \Redis();
        $this->redis->connect('127.0.0.1',6379);
    }
    /**
     * 加锁
     * @param string  $key    
     * @param integer $expire 
     */
    public function add($key, $expire = 3)
    {
        if(!$key){
            return false;
        }

        $value = 1;
        $is_lock = $this->redis->set($key, $value, ['nx', 'ex'=> $expire]);
        if($is_lock){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 事务释放
     * @param  string $key 
     * @return bool      
     */
    public function release($key){
        if(!$key){
            return false;
        }

        $this->redis->watch($key);
        if ($this->redis->get($key)) {
            $this->redis->multi()->del($key)->exec();
            return true;
        }
        $this->redis->unwatch();
        return false;
    }

    /**
     * lua释放
     * @param  string $key 
     * @return bool      
     */
    public function del($key){
        $script = <<< EOF
        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
EOF;

        $value = 1;
        //第2个参数表示传入的KEYS和ARGV
        //第3个参数表示传入的KEYS的个数
        return $this->redis->eval($script, [$key, $value], 1);
    }

    /**
     * 尝试加锁
     * @param  string   $key    
     * @param  \Closure $action 
     */
    public function try($key, \Closure $action){
        $num = 5;
        while($num >= 0){ 
            $res = $this->add($key);
            if($res) {
                $action();
                break;
            }else{
                $num--;
                sleep(1);
            }

        }
    }

    public function __destruct()
    {
        $this->redis->close();
    }
}

$lock = new Lock();
$lock->add('666666');

$del = $lock->del('666666');
var_dump($del);

$release = $lock->release('666666');
var_dump($release);

$lock->add('666666');
$lock->try('666666', function(){
    var_dump('555555');
});